/*******************************************************************************
 * Copyright (c) 2011 LegSem.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl-3.0.txt
 * 
 * Contributors:
 *     LegSem - initial API and implementation
 ******************************************************************************/
package com.legsem.legstar.jca.socket.it;

import java.math.BigDecimal;

import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.LocalTransaction;
import javax.resource.spi.ManagedConnection;

import junit.framework.TestCase;

import com.legsem.legstar.cci.LegStarConnectionSpec;
import com.legsem.legstar.cci.LegStarConnectionSpecImpl;
import com.legsem.legstar.cci.LegStarInteraction;
import com.legsem.legstar.cci.LegStarSingleIOInteractionSpec;
import com.legsem.legstar.cci.LegStarSingleIOInteractionSpecImpl;
import com.legsem.legstar.cci.socket.LegStarSocketConnectionImpl;
import com.legsem.legstar.jca.socket.LegStarSocketManagedConnectionFactoryImpl;
import com.legsem.legstar.jca.socket.LegStarSocketManagedConnectionImpl;
import com.legstar.host.invoke.model.HostProgram;
import com.legstar.messaging.HostEndpoint;
import com.legstar.test.coxb.LsfileaeCases;

public class ClientITCase extends TestCase {

    private Connection connection;

    private ConnectionFactory cxFactory;
    private ManagedConnection managedConnection;

    public void setUp() throws Exception {
        LegStarSocketManagedConnectionFactoryImpl mcf = new LegStarSocketManagedConnectionFactoryImpl();
        mcf.setServerName("mainframe");
        mcf.setPortNumber(3012);

        cxFactory = (ConnectionFactory) mcf.createConnectionFactory();
        assertNotNull(cxFactory);
        createConnections();
    }

    public void tearDown() throws Exception {
        executeLsfilear(99998);
        executeLsfilear(99999);
        connection.close();
        managedConnection.destroy();
    }

    public void testOneInteraction() throws Exception {
        executeLsfileae();
    }

    public void testMultipleInteractionsUsingSameConnection() throws Exception {
        for (int i = 0; i < 2; i++) {
            executeLsfileae();
        }
    }

    public void testMultipleInteractionsUsingDifferentConnections()
            throws Exception {
        for (int i = 0; i < 2; i++) {
            executeLsfileae();
            connection.close();
            createConnections();
        }
    }

    public void testCreateConnectionWithoutSpecs() throws Exception {
        connection.close(); // Don't need the one created in setup

        connection = cxFactory.getConnection();
        managedConnection = ((LegStarSocketConnectionImpl) connection)
                .getManagedConnection();

        HostEndpoint endpoint = ((LegStarSocketManagedConnectionImpl) managedConnection)
                .getHostEndpoint();
        assertEquals("", endpoint.getHostUserID());
        assertEquals("", endpoint.getHostPassword());
        assertFalse(endpoint.isHostTraceMode());

        executeLsfileae();
    }

    /**
     * A sequence of updates and queries using the same connection without
     * explicit demarcation (all CICS programs are executed as part of the same
     * transaction nevertheless).
     * 
     * @throws Exception
     */
    public void testUpdates() throws Exception {
        com.legstar.test.coxb.lsfileae.Dfhcommarea output = null;

        executeLsfileaw(99999);
        assertNotNull(executeLsfileae(99999));
        executeLsfilear(99999);
        output = executeLsfileae(99999);
        assertEquals(0, output.getComNumber());
    }

    /**
     * Perform 2 updates as part of a transaction that is rolled back. Make sure
     * updates are undone.
     * 
     * @throws Exception
     */
    public void testAbortedUpdates() throws Exception {
        com.legstar.test.coxb.lsfileae.Dfhcommarea output = null;

        LocalTransaction t = connection.getLocalTransaction();
        t.begin();
        output = executeLsfileaw(99998);
        assertEquals(99998, output.getComNumber());
        output = executeLsfileaw(99999);
        assertEquals(99999, output.getComNumber());
        t.rollback();
        output = executeLsfileae(99998);
        assertEquals(0, output.getComNumber());
        output = executeLsfileae(99999);
        assertEquals(0, output.getComNumber());

    }

    private void createConnections() throws Exception {
        LegStarConnectionSpec specs = new LegStarConnectionSpecImpl();
        specs.setHostUserID("P390");
        specs.setHostPassword("STREAM2");
        specs.setHostTraceMode(true);
        connection = cxFactory.getConnection(specs);
        managedConnection = ((LegStarSocketConnectionImpl) connection)
                .getManagedConnection();
    }

    private void executeLsfileae() throws Exception {
        com.legstar.test.coxb.lsfileae.Dfhcommarea output = executeLsfileae(100);
        LsfileaeCases.checkJavaObjectReply100(output);
    }

    private com.legstar.test.coxb.lsfileae.Dfhcommarea executeLsfileae(int id)
            throws Exception {
        com.legstar.test.coxb.lsfileae.Dfhcommarea input = new com.legstar.test.coxb.lsfileae.Dfhcommarea();
        input.setComNumber(id);
        return (com.legstar.test.coxb.lsfileae.Dfhcommarea) executeProgram(
                "LSFILEAE", input);
    }

    private com.legstar.test.coxb.lsfileae.Dfhcommarea executeLsfileaw(int id)
            throws Exception {
        com.legstar.test.coxb.lsfileae.Dfhcommarea input = new com.legstar.test.coxb.lsfileae.Dfhcommarea();
        input.setComNumber(id);
        input.setComAmount(new BigDecimal(id * 3.14).toString());
        input.setComDate("12111965");
        com.legstar.test.coxb.lsfileae.ComPersonal personal = new com.legstar.test.coxb.lsfileae.ComPersonal();
        personal.setComAddress(id + " street");
        personal.setComName("P" + id);
        personal.setComPhone("0123456789");
        input.setComPersonal(personal);
        return (com.legstar.test.coxb.lsfileae.Dfhcommarea) executeProgram(
                "LSFILEAW", input);
    }

    private com.legstar.test.coxb.lsfileae.Dfhcommarea executeLsfilear(int id)
            throws Exception {
        com.legstar.test.coxb.lsfileae.Dfhcommarea input = new com.legstar.test.coxb.lsfileae.Dfhcommarea();
        input.setComNumber(id);
        return (com.legstar.test.coxb.lsfileae.Dfhcommarea) executeProgram(
                "LSFILEAR", input);
    }

    private Object executeProgram(String programName, Object input)
            throws Exception {
        // Object ispec = context.lookup("jca/LegStarISpec");
        LegStarSingleIOInteractionSpec ispec = new LegStarSingleIOInteractionSpecImpl();
        HostProgram hostProgram = new HostProgram();
        hostProgram.setName(programName);
        ispec.setHostProgram(hostProgram);

        com.legstar.test.coxb.lsfileae.bind.DfhcommareaTransformers tf = new com.legstar.test.coxb.lsfileae.bind.DfhcommareaTransformers();
        ispec.setInputTransformer(tf.getJavaToHost());
        ispec.setInteractionId("1234");
        ispec.setOutputTransformer(tf.getHostToJava());

        LegStarInteraction interaction = (LegStarInteraction) connection
                .createInteraction();

        Object output = interaction.execute(ispec, input);

        interaction.close();
        return output;
    }
}
